home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Tool Chest / Development Platforms / Macintosh Common Lisp Related / User Contributions / mapforms (code walker).sea / mapforms (code walker) / subst.lisp < prev    next >
Encoding:
Text File  |  1992-04-21  |  17.8 KB  |  392 lines  |  [TEXT/CCL2]

  1. ;;; -*- Mode:LISP; Package:Language-Tools; Syntax:Common-Lisp -*-
  2. ;;;>>SHARED-MESSAGE
  3. ;;;>
  4. ;;;>******************************************************************************************
  5. ;;;>    This may only be used as permitted under the license agreement under
  6. ;;;>    which it has been distributed, and in no other way.
  7. ;;;>******************************************************************************************
  8. ;;;>
  9. ;;;>
  10. ;;; Written April 1983 by David A. Moon for use by the Common Lisp community
  11. ;;; based on a design by Alan Bawden
  12.  
  13. ;;; Lambda-binding optimizer
  14.  
  15. ;--- Common Lisp version conversion issues:
  16. ;--- Depends on CONDITION-CASE which Common Lisp doesn't have yet (for exceptions)
  17. ;--- Is someone really going to force me to use <= rather than  ?  Ugh, bletch.
  18.  
  19. ;;; The entry functions to this module are 
  20. ;;; LET-SUBST, LET*-SUBST, DEFSUBST, DEFSUBST-WITH-PARENT,
  21. ;;; ONCE-ONLY, EXPAND-SUBST-DEFINITION-INTERNAL
  22. ;;;
  23. ;;; EXPAND-SUBST-DEFINITION-INTERNAL is not exported, it's only called
  24. ;;; from SI:EXPAND-SUBST-DEFINITION.
  25.  
  26. (EXPORT '(LET-SUBST LET*-SUBST DEFSUBST DEFSUBST-WITH-PARENT ONCE-ONLY 
  27.       *LET-SUBST-DECIDE-TRACE*))
  28.  
  29.  
  30. ;;; The idea of LET-SUBST is that
  31. ;;;    (LET-SUBST vars vals form)
  32. ;;; could return
  33. ;;;    `((LAMBDA (,@vars) ,form) ,@vals)
  34. ;;; but normally it will analyze the body and the vals and substitute a val
  35. ;;; for occurrences of the corresponding var inside the body if at all possible.
  36. ;;; The vars had better not have been declared special or the analysis won't work.
  37. ;;; The expansion will not always be a LET.  If the body form needs to scope
  38. ;;; declarations or BINDs, it should contain an explicit LET or LOCALLY.
  39. (DEFUN LET-SUBST (VARS VALS FORM)
  40.   (COND ((NOT (NULL VARS))
  41.      ;; Do something reasonable if the form cannot be understood
  42.      (CONDITION-CASE (FAILURE)
  43.          ;; First see how the form uses the vars
  44.          (LET ((VARNOTES (LOOP FOR VAR IN VARS COLLECTING (MAKE-VARNOTE :NAME VAR))))
  45.            (ANNOTATE-FORM FORM VARNOTES)
  46.            ;; Then decide which variables are to be substituted    
  47.            (LET-SUBST-INTERNAL VARS VALS VARNOTES FORM T))
  48.        (FORM-NOT-UNDERSTOOD
  49.          (FORMAT *ERROR-OUTPUT* "~&LET-SUBST is punting because ~A" FAILURE)
  50.          `((LAMBDA (,@VARS) ,FORM) ,@VALS))))
  51.     (T FORM)))
  52.  
  53. ;;; LET*-SUBST is similar, but uses serial binding
  54. (DEFUN LET*-SUBST (VARS VALS FORM)
  55.   (COND ((NOT (NULL VARS))
  56.      ;; Do something reasonable if the form cannot be understood
  57.      (CONDITION-CASE (FAILURE)
  58.          ;; First see how the form uses the vars
  59.          (LET ((VARNOTES (LOOP FOR VAR IN VARS COLLECTING (MAKE-VARNOTE :NAME VAR))))
  60.            (ANNOTATE-FORM FORM VARNOTES)
  61.            ;; Then decide which variables are to be substituted    
  62.            (LET-SUBST-INTERNAL VARS VALS VARNOTES FORM NIL))
  63.        (FORM-NOT-UNDERSTOOD
  64.          (FORMAT *ERROR-OUTPUT* "~&LET*-SUBST is punting because ~A" FAILURE)
  65.          `(LET* ,(MAPCAR #'LIST VARS VALS) ,FORM))))
  66.     (T FORM)))
  67.  
  68. (DEFUN LET-SUBST-INTERNAL (VARS VALS VARNOTES FORM PARALLEL)
  69.   (LET* (;; Decide which variables are to be substituted
  70.      ;; DECISIONS is a list parallel to VARS and VALS
  71.      ;; Each element of this list is a list (substp notepad freevars)
  72.      ;;  substp is T if the value is to be substituted, NIL if not
  73.      ;;  notepad is the annotation of the value
  74.      ;;  freevars is the list of variables used freely by the value
  75.      (DECISIONS (LET-SUBST-DECIDE VARS VALS VARNOTES VARNOTES PARALLEL))
  76.      ;; Collect the variables that are used free by the forms that
  77.      ;; are getting substituted into the FORM
  78.      (FREE-VARS (LOOP FOR (SUBSTP VALUE-NOTEPAD FREE) IN DECISIONS
  79.               WHEN SUBSTP
  80.                 APPEND FREE))
  81.      ;; This special variable accumulates the substitutions to be done
  82.      (SUBSTITUTIONS NIL)
  83.      ;; Collect the bindings for the unsubstituted variables.
  84.      ;; This may involve renaming non-substituted variables that conflict with
  85.      ;; substituted forms that are now being moved inside their scope.
  86.      (LETS (LOOP FOR (SUBSTP) IN DECISIONS
  87.              FOR VAR IN VARS
  88.              FOR VAL IN VALS
  89.              DO (AND (NOT PARALLEL)
  90.                  SUBSTITUTIONS
  91.                  (SETQ VAL (LET-SUBST-COPYFORMS SUBSTITUTIONS VAL)))
  92.              WHEN (NOT SUBSTP)            ;This variable isn't going away
  93.                DO (WHEN (MEMBER VAR FREE-VARS)    ;Does it need to be renamed?
  94.                 (PUSH (CONS VAR (SETQ VAR (GENSYM))) SUBSTITUTIONS))
  95.                AND COLLECT (LIST VAR VAL)
  96.              ELSE DO (PUSH (CONS VAR VAL) SUBSTITUTIONS))))
  97.     ;; Generate the substituted FORM
  98.     (WHEN SUBSTITUTIONS
  99.       (SETQ FORM (LET-SUBST-COPYFORMS SUBSTITUTIONS FORM)))
  100.     ;; Three cases: no LET required, no LET variables used in FORM, or a LET is required
  101.     (COND ((NULL LETS) FORM)
  102.       ((LOOP FOR (SUBSTP) IN DECISIONS AND VARNOTE IN VARNOTES
  103.          ALWAYS (OR SUBSTP (ZEROP (VARNOTE-N-USAGES))))
  104.        `(PROGN ,@(MAPCAR #'CADR LETS) ,FORM))
  105.       (T `(,(IF PARALLEL `LET `LET*) ,LETS
  106.         ,FORM)))))
  107.  
  108. (DEFUN LET-SUBST-COPYFORMS (SUBSTITUTIONS BODY)
  109.   (FLET ((LET-SUBST-COPY
  110.        (FORM KIND IGNORE)
  111.        (DECLARE (SYS:DOWNWARD-FUNCTION))
  112.        (BLOCK LET-SUBST-COPY
  113.          (CASE KIND
  114.            (SYMEVAL
  115.          (LET ((TEM (ASSOC FORM SUBSTITUTIONS)))
  116.            (WHEN TEM
  117.              (RETURN-FROM LET-SUBST-COPY (VALUES (CDR TEM) T)))))    ;Make substitution and don't subst inside it
  118.            ((SET LET)
  119.         (WHEN (ASSOC FORM SUBSTITUTIONS)
  120.           (ERROR "Attempt to set or bind the SUBST parameter ~S." FORM))))
  121.          FORM)))
  122.     (COPYFORMS #'LET-SUBST-COPY BODY)))
  123.  
  124. ;For EXPAND-SUBST-DEFINITION
  125. (DEFVAR *INNOCUOUS-VARNOTE* (MAKE-VARNOTE :NAME '*INNOCUOUS-VARNOTE*
  126.                       :N-USAGES 1))
  127.  
  128. ;A debugging feature
  129. (DEFVAR *LET-SUBST-DECIDE-TRACE* NIL)
  130.  
  131. ;Replace this (in LET-SUBST-DECIDE) with AND to dike out the tracing code
  132. (DEFMACRO LET-SUBST-DECIDE-TRACE-HACK (&REST FORMS)
  133.   (COND ((NULL FORMS) T)
  134.     ((NULL (CDR FORMS)) (CAR FORMS))
  135.     (T (LET ((FORM (CAR FORMS)))
  136.          (AND (LISTP FORM) (EQ (FIRST FORM) 'SI:DISPLACED)
  137.           (SETQ FORM (THIRD FORM)))       
  138.          `(COND (,FORM (LET-SUBST-DECIDE-TRACE-HACK . ,(CDR FORMS)))
  139.             (*LET-SUBST-DECIDE-TRACE*
  140.              (FORMAT *TRACE-OUTPUT*
  141.                  "~2&~S returned NIL, hence ~S will not be substituted for ~S.~@
  142.                    ~@{~S=~S~^, ~}~2%"
  143.                  ',(COPY-LIST FORM)    ;to avoid displacement
  144.                  VAL VAR
  145.                  . ,(LOOP FOR ARG IN (CDR FORM)
  146.                       COLLECT `',ARG
  147.                       COLLECT `,ARG))
  148.              NIL))))))
  149.  
  150. ;; Decide which values may be substituted in.
  151. ;; This has to be done right to left (by recursion) so that we know
  152. ;; whether we will be moving a value past any value to its right, and
  153. ;; so that with serial binding the forms to the right of a variable
  154. ;; act like part of the body as far as that variable is concerned.
  155. (DEFUN LET-SUBST-DECIDE (VARS VALS VARNOTES RIGHT-VARNOTES PARALLEL &AUX VNP)
  156.   (WHEN RIGHT-VARNOTES
  157.     (LET ((VAR (POP VARS))
  158.       (VAL (POP VALS))
  159.       (VARNOTE (OR (CAR RIGHT-VARNOTES) *INNOCUOUS-VARNOTE*))
  160.       (DECISIONS (LET-SUBST-DECIDE VARS VALS VARNOTES (CDR RIGHT-VARNOTES) PARALLEL)))
  161.       VAR ;not actually used
  162.       ;; Now we have the value form to be substituted, the information
  163.       ;; about where it will go, and the decisions for the values
  164.       ;; to its right.  Analyze the value form.
  165.       (MULTIPLE-VALUE-BIND (NOTEPAD FREE-VARIABLES FREE-BLOCKS FREE-TAGS REPLICABILITY)
  166.       (ANNOTATE-FORM VAL (AND (NOT PARALLEL)
  167.                   (LDIFF VARNOTES RIGHT-VARNOTES)))
  168.     (LET ((DECISION
  169.            (LET-SUBST-DECIDE-TRACE-HACK
  170.             ;; Variable has not been used in an unsubstitutable way
  171.             (SETQ VNP (VARNOTE-NOTEPAD))
  172.             ;; Value does not have a free variable reference captured by body form
  173.             ;(DISJOINT-SETS FREE-VARIABLES (VARNOTE-VARIABLE-ENV))
  174.             ;; The above test is made stronger to allow for the fact that
  175.             ;; an arbitrary side-effect might be influenced by the binding
  176.             ;; of a special variable.  Here we assume that all variables
  177.             ;; in varnote-variable-env might have been declared special,
  178.             ;; had their LOCF taken, or otherwise be "global" in scope.
  179.             (DISJOINT-SETS (NOTEPAD-READ) (VARNOTE-VARIABLE-ENV))
  180.             (DISJOINT-SETS (NOTEPAD-WRITTEN) (VARNOTE-VARIABLE-ENV))
  181.             ;; No captured free block references
  182.             (DISJOINT-SETS FREE-BLOCKS (VARNOTE-BLOCK-ENV))
  183.             ;; No captured free go tag references
  184.             (DISJOINT-SETS FREE-TAGS (VARNOTE-TAG-ENV))
  185.             ;; Either no side-effects and not evaluated so many times as to hurt
  186.             ;; code density, or has side-effects but is evaluated exactly once.
  187.             (IF (NOTEPAD-WRITTEN)
  188.             (AND (= (VARNOTE-N-USAGES) 1)
  189.                  (NOT (NOTEPAD-CONTROL VNP)))
  190.             (<= (VARNOTE-N-USAGES) REPLICABILITY))
  191.             ;; May pass over everything that happens from the beginning of
  192.             ;; the body up to the last place the variable appears.
  193.             (DISJOINT-NOTES VNP NOTEPAD)
  194.             ;; May pass over values to its right
  195.             (LOOP WITH PASSED = (NOTEPAD-SUBSTS VNP)
  196.               FOR (SUBSTP PAD) IN DECISIONS
  197.               FOR VAR IN VARS
  198.               WHEN (OR (NOT SUBSTP)        ;Would pass over form in LET
  199.                    (MEMBER VAR PASSED))    ;Would pass over substituted form
  200.                 ALWAYS (DISJOINT-NOTES PAD NOTEPAD)))))
  201.       (CONS (LIST DECISION NOTEPAD FREE-VARIABLES) DECISIONS))))))
  202.  
  203. ;;;; DEFSUBST
  204.  
  205. #+LISPM (PROGN 'COMPILE        ;Only the Lisp Machine compiler understands substs
  206.  
  207. ;; The predigested form of the subst is stored in the debug-info of the function.
  208. ;; During compilation it is also stored in the file-local declarations.
  209. ;; In either case this is a list, called a subst-definition, that looks like
  210. ;;    (SUBST-DEFINITION lambda-list vars varnotes body)
  211. ;;  lambda-list is the original lambda-list
  212. ;;  vars is a list of the variables by themselves (cons it once since it's needed later)
  213. ;;  varnotes is a list of varnotes for each variable, or of NIL if the variable may always
  214. ;;   be substituted, or NIL as the whole list if all the elements are NIL
  215. ;;  body is a single form
  216.  
  217. (DEFPROP SUBST-DEFINITION T SI:DEBUG-INFO)
  218.  
  219. ;--- Temporary while this is being used to clobber LMMAC.  Suppress redefinition warnings.
  220. (SYS:RECORD-SOURCE-FILE-NAME 'DEFSUBST-WITH-PARENT 'ZL:DEFUN T)
  221.  
  222.  
  223. ;; (DEFSUBST name (args...) body)
  224. ;; is the same as DEFUN except that the function will be open-coded
  225. ;; body may be preceded by a documentation string and documentation-type declarations.
  226. ;; Other declarations are not permitted since they will not be included in
  227. ;; the open-coded version.  Declaration of the
  228. ;; the args variables is not allowed, since they can be optimized out.  To include
  229. ;; declarations in the body, wrap it in a LOCALLY or a LET.
  230. ;; After the documentation and declarations, the body may contain multiple forms,
  231. ;; which will be wrapped in a PROGN when the function is open-coded.
  232.  
  233. ;(DEFMACRO DEFSUBST (FUNCTION LAMBDA-LIST &BODY BODY)
  234. ; defined in BOOT
  235.  
  236. (DEFUN EXPAND-DEFSUBST (FUNCTION LAMBDA-LIST BODY &AUX (VARS NIL) FORM)
  237.   ;; Only symbols work as names, not general function specs [contrary to the manual]
  238.   (CHECK-TYPE FUNCTION SYMBOL)
  239.   ;; Only &OPTIONAL, &KEY, and &REST work in the lambda list.  Supplied-p doesn't work.
  240.   ;; We may as well do all the rest of the lambda-list syntax checks, even though
  241.   ;; the compiler will do some of them when the function is compiled.
  242.   (LOOP FOR L ON LAMBDA-LIST AS X = (CAR L) WITH OPTIONAL = NIL WITH KEY = NIL DO
  243.     (COND ((EQ X '&OPTIONAL)
  244.        (SETQ OPTIONAL T))
  245.       ((EQ X '&KEY)
  246.        (SETQ KEY T))
  247.       ((EQ X '&REST)
  248.        (AND (OR (NOT (= (LIST-LENGTH L) 2))
  249.             (NOT (SYMBOLP (CADR L))))
  250.         (DEFSUBST-ERROR FUNCTION T "(...~{~S~^ ~}) is illegal use of &REST" L))
  251.        (PUSH (CADR L) VARS))
  252.       ((MEMBER X LAMBDA-LIST-KEYWORDS)
  253.        (DEFSUBST-ERROR FUNCTION T "The keyword ~S is inappropriate in a DEFSUBST" X))
  254.       ((SYMBOLP X)
  255.        (PUSH X VARS))
  256.       ((OR (ATOM X)
  257.            (NOT (OR OPTIONAL KEY))
  258.            (NOT (OR (SYMBOLP (CAR X))
  259.             (AND KEY (CONSP (CAR X)) (SYMBOLP (CAAR X)) (SYMBOLP (CADAR X))))))
  260.        (DEFSUBST-ERROR FUNCTION T "~S appears where a variable is expected" X))
  261.       ((NULL (CDR X))
  262.        (PUSH (IF (SYMBOLP (CAR X)) (CAR X) (CADAR X)) VARS))
  263.       ((CDDR X)
  264.        (DEFSUBST-ERROR FUNCTION T "Supplied-p variables ~S do not work in DEFSUBST." X))
  265.       (T        ;Optional or keyword argument with initialization
  266.        (MULTIPLE-VALUE-BIND (NIL FREE) (ANNOTATE-FORM (CADR X))
  267.          (IF (INTERSECTION FREE VARS)
  268.          (DEFSUBST-ERROR FUNCTION T 
  269.                  "The binding ~S depends on sequential binding, which does~@
  270.                   not currently work in DEFSUBST."
  271.                  X)))
  272.        (PUSH (IF (SYMBOLP (CAR X)) (CAR X) (CADAR X)) VARS))))
  273.   (SETQ VARS (NREVERSE VARS))
  274.   (IF (EQUAL VARS LAMBDA-LIST)            ;Save storage later
  275.       (SETQ VARS LAMBDA-LIST))
  276.   (AND (MEMBER '&KEY LAMBDA-LIST :TEST #'EQ) (MEMBER '&REST LAMBDA-LIST :TEST #'EQ)
  277.        (DEFSUBST-ERROR FUNCTION T "&KEY and &REST cannot be used together in a DEFSUBST"))
  278.   ;; Parse off the declarations, converting BODY into FORM
  279.   (LOOP WITH BOD = BODY
  280.     DO (COND ((AND (STRINGP (CAR BOD)) (CDR BOD))    ;Documentation string
  281.           (SETQ BOD (CDR BOD)))
  282.          ((AND (LISTP (CAR BOD)) (EQ (CAAR BOD) 'DECLARE))
  283.           (DOLIST (DCL (CDAR BOD))
  284.             (UNLESS (AND (LISTP DCL)    ;Something like (DECLARE (ARGLIST ...))
  285.                  (SYMBOLP (CAR DCL))
  286.                  (GET (CAR DCL) 'SI:DEBUG-INFO))
  287.               (DEFSUBST-ERROR FUNCTION NIL
  288.                       "The declaration ~S will not work, because it~@
  289.                        will not be included when the function is ~
  290.                        substituted in-line."
  291.                       DCL)))
  292.           (SETQ BOD (CDR BOD)))
  293.          (T (SETQ FORM (IF (= (LIST-LENGTH BOD) 1) (FIRST BOD) (CONS 'PROGN BOD)))
  294.             (RETURN))))
  295.   ;; Analyze the body, similarly to first part of LET-SUBST, and produce a subst-definition
  296.   (LET ((VARNOTES (LOOP FOR VAR IN VARS COLLECT (MAKE-VARNOTE :NAME VAR))))
  297.     (ANNOTATE-FORM FORM VARNOTES)
  298.     ;; Smash the varnote for any variable that has no constraints on substitution
  299.     ;; since this is actually the usual case, e.g. for most defstruct accessors
  300.     (LOOP FOR L ON VARNOTES AS VARNOTE = (CAR L) WITH VNP DO
  301.       (AND (SETQ VNP (VARNOTE-NOTEPAD))    ;Variable isn't used in some horrible way
  302.        (NULL (VARNOTE-VARIABLE-ENV))    ; and isn't used inside a lexical contour
  303.        (NULL (VARNOTE-BLOCK-ENV))        ; of any of the three kinds
  304.        (NULL (VARNOTE-TAG-ENV))
  305.        (= (VARNOTE-N-USAGES) 1)        ; and is only used once
  306.        (NOT (NOTEPAD-CONTROL VNP))        ; and isn't inside control structure
  307.        (NULL (NOTEPAD-READ VNP))        ; and isn't used after side-effects
  308.        (NULL (NOTEPAD-WRITTEN VNP))
  309.        (LOOP FOR (VAR) IN (CDR L)        ; and isn't used out of order with
  310.          NEVER (MEMBER VAR (NOTEPAD-SUBSTS VNP)))    ; the variables to its right
  311.        (SETF (CAR L) NIL)))
  312.     (AND (LOOP FOR X IN VARNOTES ALWAYS (NULL X))
  313.      (SETQ VARNOTES NIL))            ;All varnotes smashed
  314.     ;; Build the structure needed later to open-code this function
  315.     (LET ((SUBST-DEFINITION (LIST 'SYS:SUBST-DEFINITION LAMBDA-LIST VARS VARNOTES FORM)))
  316.       ;; If this is for a compilation, check that it wasn't previously assumed a function.
  317. ;      (COMPILER:MAYBE-WARN-ABOUT-MACRO-DEFINITION FUNCTION SUBST-DEFINITION)
  318.       ;; Tell the world about it
  319.       `(PROGN 'COMPILE
  320.           (EVAL-WHEN (COMPILE)
  321.         (COMPILER:FILE-DECLARE ',FUNCTION 'ZL:DEF ',SUBST-DEFINITION))
  322.           (DEFUN ,FUNCTION ,LAMBDA-LIST
  323.         (DECLARE ,SUBST-DEFINITION)
  324.         . ,BODY)))))
  325.  
  326. ;This is for defstruct (or anything else that writes substs automatically
  327. ;as part of the expansion of some other form).
  328. ;PARENT is a list of the parent definition name and its definition type.
  329. ;Also accepted is a symbol, which is what it used to be (for old compiled defstructs).
  330. (DEFMACRO DEFSUBST-WITH-PARENT (FUNCTION PARENT LAMBDA-LIST &BODY BODY)
  331.   (IF (NOT (LISTP PARENT)) (SETQ PARENT (LIST PARENT)))
  332.   `(DEFSUBST ,FUNCTION ,LAMBDA-LIST
  333.      (DECLARE (FUNCTION-PARENT ,@PARENT))
  334.      . ,BODY))
  335.  
  336. ;Report errors in the DEFSUBST macro in a nice way, hooked up with the compiler
  337. (DEFUN DEFSUBST-ERROR (FUNCTION FATAL FORMAT-STRING &REST FORMAT-ARGS)
  338.   (LET ((COMPILER:DEFAULT-WARNING-FUNCTION FUNCTION)
  339.     (COMPILER:DEFAULT-WARNING-DEFINITION-TYPE 'ZL:DEFUN))
  340.     (APPLY #'COMPILER:WARN (AND FATAL '(:ERROR T)) FORMAT-STRING FORMAT-ARGS)))
  341. (DEFPROP DEFSUBST-ERROR T :ERROR-REPORTER)
  342.  
  343. ;; Expand a call to a SUBST function.
  344. ;; SUBST is the subst-definition to use; FORM is the whole form.
  345. ;; This is called by SI:EXPAND-SUBST-DEFINITION as an interface into the language tools.
  346. (DEFUN EXPAND-SUBST-DEFINITION-INTERNAL (VARS VALS VARNOTES BODY)
  347.   ;; Plug in values in one of two different ways depending on whether it
  348.   ;; is necessary to do code analysis of the values.  In the usual case
  349.   ;; all the varnotes would be innocuous and no analysis is required.
  350.   (IF VARNOTES
  351.       ;; Do a LET-SUBST, except that the body has already been analyzed
  352.       (LET-SUBST-INTERNAL VARS VALS VARNOTES BODY T)
  353.       ;; Plug them all in.  Don't use SUBLIS to avoid name clashes with non-variables.
  354.       (LET-SUBST-COPYFORMS (PAIRLIS VARS VALS) BODY)))
  355.  
  356. );#+LISPM
  357.  
  358. ;;;; ONCE-ONLY
  359.  
  360. ;See page 222 of the Chine Nual.  Admittedly the documentation there is incomprehensible.
  361.  
  362. ;;; Create code that is body, possibly with a lambda wrapped around it to make
  363. ;;; sure that the forms assigned to the listed variables only get evaluated once.
  364. #-EXPLORER
  365. (DEFMACRO ONCE-ONLY (VARIABLE-LIST &BODY BODY)
  366.   ;; Check the syntax of the macro-call that invoked us
  367.   (DOLIST (VARIABLE VARIABLE-LIST)
  368.     (OR (VARIABLEP VARIABLE)
  369.     (ERROR "~S is not a variable" VARIABLE)))
  370.   ;; Generate code that evaluates the body with each variable bound to a gensym
  371.   ;; then uses LET-SUBST to remove the gensyms where possible.  When a gensym cannot
  372.   ;; be removed, the form returned by the body is wrapped in a binding of the gensym.
  373.   ;; The gensyms need to be distinct from any expression that might get incorporated
  374.   ;; into the result of the body, so we have to make new gensyms on every invocation.
  375.   ;; If we were willing to make two copies of the body, we could have a special case
  376.   ;; for when the values of all the variables are atoms (variables or constants)
  377.   ;; in which case no let-subst and no gensyms are required.  But this doesn't
  378.   ;; seem worthwhile.
  379.   `(LET ((ONCE-ONLY-TEMPS (LIST . ,(LOOP FOR L ON VARIABLE-LIST COLLECT `(GENSYM)))))
  380.      (LET-SUBST ONCE-ONLY-TEMPS
  381.         (LIST . ,VARIABLE-LIST)
  382.         (LET ,(LOOP FOR VAR IN VARIABLE-LIST
  383.                 COLLECT `(,VAR (POP ONCE-ONLY-TEMPS)))
  384.           . ,BODY))))
  385.  
  386. ;;; Utility for macroexpanding a whole form...
  387.  
  388. #-EXPLORER
  389. (DEFUN MACROEXPAND-ALL (FORM)
  390.   (COPYFORMS #'(LAMBDA (X &REST IGNORE) X) FORM :EXPAND-ALL-MACROS T))
  391.  
  392.